feat(clojure): add full Clojure port at TS-canonical parity#74
Merged
Conversation
Add a Clojure implementation of voxgig/struct that is a faithful port of
the canonical TypeScript (modelled on the Python port, which shares
Clojure's single-nil world). All 1329 shared-corpus cases pass and the
port defines every canonical public function.
- Nodes are mutable java.util.LinkedHashMap / ArrayList to preserve the
reference-stable in-place mutation the algorithm depends on.
- nil unifies undefined and JSON null; Group A/B rules and a NOARG
sentinel recover the distinctions where they matter.
- Lower-smushed public names match the canonical export list, so
tools/check_parity.py matches case/underscore-insensitively.
- Zero third-party runtime deps; the test runner ships an in-tree JSON
reader and the shared runner logic (clojure -M:test).
Wire-up: clojure/{src,test,deps.edn,Makefile,README,DOCS,AGENTS}; add
clojure to check_parity.py (COMPLETE_PORTS + a (defn ...) extractor),
the top-level Makefile LANGS/PUBLISH_LANGS, and the README/AGENTS/REPORT
parity tables; ignore clojure build artifacts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
Add an OCaml implementation of voxgig/struct that is a faithful port of the
canonical TypeScript. Like TS (and Rust), OCaml keeps undefined (Noval) and
JSON null (Null) distinct, so this port mirrors the canonical logic directly.
All 1329 shared-corpus cases pass and the port defines every canonical
public function.
- A single `value` variant models JSON-shaped data; nodes are mutable and
reference-stable (lists are `value list ref`, maps an in-tree ordered map),
so the in-place algorithms behave identically to the reference.
- Group A readers (getprop/getelem/haskey) collapse Null to "no value";
Group B processors use the raw `lookup_` to preserve Null.
- Numbers are a single `Num of float` with Number.isInteger semantics.
- Lower-smushed / snake_cased public names match the canonical export list
case/underscore-insensitively (check_placement = checkPlacement, etc.).
- Zero third-party deps: in-tree JSON reader for the runner and an in-tree
RE2-subset backtracking regex engine (vregex.ml) for $LIKE and re_*.
Wire-up: ocaml/{src,test,Makefile,README,DOCS,AGENTS}; add ocaml to
check_parity.py (COMPLETE_PORTS + a let/and extractor), the top-level Makefile
LANGS/PUBLISH_LANGS, and the README/AGENTS/REPORT parity tables; ignore OCaml
build artifacts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
Add a Scala 3 implementation of voxgig/struct that is a faithful port of the
canonical TypeScript (ported from the OCaml port). Like TS/Rust/OCaml, Scala
keeps undefined (Noval) and JSON null (VNull) distinct, so this port mirrors
the canonical logic directly. All 1329 shared-corpus cases pass and the port
defines every canonical public function.
- A single sealed `Value` ADT models JSON-shaped data; nodes are mutable and
reference-stable (lists are ArrayBuffer, maps a mutable LinkedHashMap that
preserves insertion order), so the in-place algorithms behave identically.
- Group A readers (getprop/getelem/haskey) collapse VNull to "no value";
Group B processors use the raw `lookup_` to preserve VNull.
- Numbers are a single VNum(Double) with Number.isInteger semantics.
- Lower-smushed / camelCased public names match the canonical export list
case/underscore-insensitively (checkPlacement, injectorArgs, injectChild).
- Zero third-party deps: in-tree JSON reader for the runner and the JVM
stdlib java.util.regex for $LIKE and the re_* API.
Wire-up: scala/{src,test,Makefile,README,DOCS,AGENTS}; add scala to
check_parity.py (COMPLETE_PORTS + a `def` extractor), the top-level Makefile
LANGS/PUBLISH_LANGS, and the README/AGENTS/REPORT parity tables; ignore Scala
build artifacts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
Promote Java and Kotlin from "Partial" to "Complete": both define the full canonical API and now pass the shared build/test corpus in full. Java had 6 genuine corpus failures (the "trails canonical by a release" gap), all in the test runner's null handling rather than the library: - The corpus runner encoded an *absent* input as the "__NULL__" marker; it now leaves an absent `in` as UNDEF so subjects see "undefined" (fixes walk.basic with no input). - minor.stringify and minor.pathify ran with null:true; the canonical harness runs them with null:false so a JSON-null value stays a real null (stringify -> "null", pathify -> "<unknown-path:null>", null path parts dropped). Java now passes 1300/1300; baseline refreshed. Kotlin already passed the corpus in full (1315/1315) — no code change needed. Move both ports from PARTIAL_PORTS to COMPLETE_PORTS in check_parity.py (still `ok`), and update the README/AGENTS/REPORT status tables and the per-port README/AGENTS notes accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
Add a Dart implementation of voxgig/struct that is a faithful port of the
canonical TypeScript. Dart has a single `null`, so this port follows the
Python/Clojure single-null model: `null` represents both the canonical
`undefined` and JSON `null`, with the Group A/B rules recovering the
distinction. All 1329 shared-corpus cases pass and the port defines every
canonical public function.
- Nodes are native Dart collections — `Map<String, dynamic>` (a LinkedHashMap,
insertion-ordered) and growable `List<dynamic>` — which are mutable and
reference-stable, exactly as the algorithm requires.
- Group A readers (getprop/getelem/haskey) collapse null to "no value";
Group B processors use the raw `_lookup` to preserve null. A public
`pathifyNoArg` sentinel distinguishes "no argument" from null for
typify/stringify/pathify.
- JSON integers are `int`, decimals `double`; typify treats a whole double as
an integer (Number.isInteger semantics); stringify/jsonify follow JS number
formatting.
- Zero third-party deps: library uses only dart:core (incl. RegExp); the test
runner reads the corpus with the SDK dart:convert.
Wire-up: dart/{lib,test,pubspec.yaml,Makefile,README,DOCS,AGENTS}; add dart to
check_parity.py (COMPLETE_PORTS; the generic name(...) extractor matches Dart
functions), the top-level Makefile LANGS/PUBLISH_LANGS, and the
README/AGENTS/REPORT parity tables; ignore Dart build artifacts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
Faithful Elixir port of the canonical TypeScript implementation, passing
the entire shared corpus (1329/1329) with zero third-party runtime
dependencies (only Elixir/OTP: ETS for the heap, core Regex).
The BEAM has no mutable, reference-stable native collection, so nodes are
kept in a small ETS-backed heap: a node is a tagged reference
({:vmap, id} / {:vlist, id}) whose contents are replaced on mutation while
the reference stays stable, emulating the canonical shared-reference
semantics. Like the Python/Clojure/Dart ports, Elixir has a single nil for
both undefined and JSON null; the Group A/B rules plus a NOARG sentinel
recover the distinction.
- elixir/lib/voxgig_struct.ex: the full library (all 48 canonical functions)
- elixir/test/runner.exs: corpus runner with a small hand-written JSON parser
(no Jason/Poison) reading the corpus straight into heap nodes
- elixir/{Makefile,README.md,DOCS.md,AGENTS.md}: build + docs
- Wire into tools/check_parity.py, top Makefile, README, AGENTS, REPORT,
.gitignore
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
Faithful Haskell port of the canonical TypeScript implementation, passing
the entire shared corpus (1329/1329) with zero third-party dependencies
(only GHC boot libraries: base, array).
Haskell has no mutable, reference-stable native collection, so a node
carries an IORef to its contents (VList holds IORef [Value], VMap holds
IORef of ordered pairs) — the analog of OCaml's ref or Rust's Rc<RefCell> —
and the whole API therefore runs in IO. Like the OCaml/Scala ports, the
canonical undefined (VNoval) and JSON null (VNull) are distinct
constructors, so the port mirrors the canonical logic directly.
- haskell/src/VoxgigStruct.hs: the full library (all 48 canonical functions)
- haskell/src/Vregex.hs: in-tree RE2-subset backtracking regex engine
- haskell/test/Runner.hs: corpus runner with a hand-written JSON reader
(no aeson) building IORef-backed nodes directly
- haskell/{Makefile,README.md,DOCS.md,AGENTS.md}: build + docs
- Wire into tools/check_parity.py (new _HASKELL_DECL extractor for top-level
type signatures), top Makefile, README, AGENTS, REPORT, .gitignore
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a Clojure implementation of voxgig/struct that is a faithful port of
the canonical TypeScript (modelled on the Python port, which shares
Clojure's single-nil world). All 1329 shared-corpus cases pass and the
port defines every canonical public function.
reference-stable in-place mutation the algorithm depends on.
sentinel recover the distinctions where they matter.
tools/check_parity.py matches case/underscore-insensitively.
reader and the shared runner logic (clojure -M:test).
Wire-up: clojure/{src,test,deps.edn,Makefile,README,DOCS,AGENTS}; add
clojure to check_parity.py (COMPLETE_PORTS + a (defn ...) extractor),
the top-level Makefile LANGS/PUBLISH_LANGS, and the README/AGENTS/REPORT
parity tables; ignore clojure build artifacts.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01GpdHxY9WrVtJv7v8bntrVZ